package com.springboot.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

/**
 * @author yexi
 */
@Service
public class UserService {

    @Autowired
    private ArticleService articleService;

    /**
     * {@code @Cacheable}:
     * 用于标记一个方法或一个类中的所有方法的返回值可以被缓存。
     * 当方法再次被调用时，若传入参数与之前调用时相同，则直接从缓存中获取结果，而不是执行方法并计算结果。
     * TIPS: 如果是无参方法，则必然被缓存
     */
    @Cacheable(cacheNames = "users")
    public String getUser() {
        System.out.println("getUser()方法被调用，通过从数据库或者其他数据源查询用户数据并返回");
        System.out.println("成功获取文章数据: " + articleService.getArticle());
        return "查询到的用户信息";
    }

    /**
     * key属性: 指定缓存的key值，获取缓存仅以key指定的形参为准，不会被其他多余参数影响
     */
    @Cacheable(cacheNames = "users", key = "#id")
    public String getUserById(Long id, String otherParam) {
        System.out.println("getUserById()方法被调用，传入参数为: " + id);
        System.out.println("成功获取文章数据: " + articleService.getArticleByUserId(id));
        return "查询到的用户信息";
    }

    /**
     * 未指定key属性，所以将params1+params2作为key值。
     */
    @Cacheable(cacheNames = "users")
    public String getUserByParams(String params1, String params2) {
        System.out.println("getUserByParams()方法被调用，传入参数为: " + params1 + "和" + params2);
        return "查询到的用户信息";
    }

    /**
     * {@code @CachePut}:
     * 用于标记一个方法的返回值可以被缓存，注意的是此方法必然会被执行并计算结果，最后再将结果保存到缓存中，适用于更新缓存数据的场景。
     * 作用:
     * 1、缓存控制更加简单。只要添加上该注解，Spring就可以自动为我们更新缓存数据，而无需手动编写更新缓存的代码。
     * 2、避免脏数据。可以保证缓存中的数据与数据库中的数据一致。这样可以避免使用过期的缓存数据，从而避免出现脏数据的情况。
     * 3、操作灵活。通过指定key属性等方式，可以灵活地控制根据不同的缓存键来分别处理缓存更新的逻辑。
     * TIPS:
     * 由于是返回值被缓存，所以不要将方法返回值设置成void，否则更新的缓存值就是null。
     */
    @CachePut(cacheNames = "users", key = "#id")
    public String updateDataById(Long id) {
        System.out.println("处理更新用户信息逻辑，传入参数: " + id);
        return "缓存更新后的用户信息";
    }

    /**
     * {@code @CacheEvict}:
     * 用于从缓存中删除数据，可以配置成在方法执行前或执行后触发，适用于需要清除缓存数据的场景。
     */
    @CacheEvict(cacheNames = "users", key = "#id")
    public void deleteDataById(Long id) {
        System.out.println("处理删除用户信息逻辑，传入参数: " + id);
    }

}
